<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
<style>
  .btn {
    outline: none;
    border: none;
    cursor: pointer;
    padding: 5px 12px;
  }
  .btn-text {
    color: #409eff;
    background-color: transparent;
  }
  .btn-text:hover {
    color: #66b1ff;
  }
</style>
<div id="app">
  <!-- 将实例中 fields & goods 传入组件 -->
  <fly-table :fields="fields" :goods="goods">
    <span slot="title">Fly Table Component</span>
  </fly-table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
  Vue.component('fly-table', {
    props: { // 组件接收外界传入的参数
      fields: {
        type: Array,
        default () {
          return []
        }
      },
      goods: {
        type: Array,
        default () {
          return []
        }
      }
    },
    methods: {
      reverse () { // 定义数组倒序方法
        this.goods.reverse()
      }
    },
    render (createElement) { // 使用render函数渲染DOM
      /**
       * createElement 可接收三个参数
       * 1. HTML标签字符串（String）| 组件选项对象（Object）| 节点解析函数（Function）
       * 2. 定义节点特性的对象（Object）
       * 3. 子节点，createElement构建的VNode节点或字符串生成的无标签文本节点（Array|String）
       */
      return createElement('div', {
        // * 作为子组件时的插槽名称
        slot: 'fly-table'
      }, [
        createElement('h2' ,this.$slots.title),
        createElement('button', {
          // class 用于绑定类名，同v-bind:class的绑定方式
          class: ['btn', 'btn-text'],
          // attrs 用于绑定节点一般属性，如id、disabled、title等
          attrs: {
            disabled: false,
            title: '点击使数组倒序'
          },
          // domProps 用于绑定节点DOM属性，如innerHTML、innerText等
          domProps: {
            innerText: '倒序'
          },
          on: {
            // 绑定事件，使用箭头函数以免创建函数作用域
            click: () => {
              this.goods.reverse()
            }
          },
          // 自定义指令
          directives: [],
          // 其他属性
          key: 'btnReverse',
          ref: 'btnReverse'
        }),
        createElement('table', {
          // style 用于绑定样式，同v-bind:style的绑定方式
          style: {
            width: '400px',
            textAlign: 'left',
            lineHeight: '42px',
            border: '1px solid #eee',
            userSelect: 'none'
          }
        }, [
          createElement('tr', [
            this.fields.map(field => createElement('th', field.prop))
          ]),
          this.goods.map(item => createElement('tr', {
            style: {
              color: item.isMarked ? '#ea4335' : ''
            }
          }, this.fields.map(field => createElement('td', {
            style: {
              borderTop: '1px solid #eee'
            }
          }, [
            field.prop !== 'operate' // 如果不是操作列，显示文本
              ? createElement('span', item[field.prop])
              : createElement('button', { // 否则显示按钮
                class: ['btn', 'btn-text'],
                domProps: {
                  innerHTML: '<span>切换标记</span>'
                },
                on: {
                  click: () => { // 当按钮被点击时，切换该行文本标记状态（被标记时字体颜色为红色）
                    item.isMarked = !item.isMarked
                  }
                }
              })
          ]))))
        ])
      ])
    }
  })
  // 声明 Vue 实例
  let vm = new Vue({
    el: '#app',
    data () {
      return {
        fields: [
          {
            label: '名称',
            prop: 'name'
          },
          {
            label: '数量',
            prop: 'quantity'
          },
          {
            label: '价格',
            prop: 'price'
          },
          {
            label: '',
            prop: 'operate'
          }
        ],
        goods: [
          {
            name: '苹果',
            quantity: 200,
            price: 6.8,
            isMarked: false
          },
          {
            name: '西瓜',
            quantity: 50,
            price: 4.8,
            isMarked: false
          },
          {
            name: '榴莲',
            quantity: 0,
            price: 22.8,
            isMarked: false
          }
        ]
      }
    }
  })
</script>
</body>
</html>